# -*- coding: utf-8 -*-
"""
@Time    : 2024/7/9 14:53 
@Author  : ZhangShenao 
@File    : param_passing.py 
@Desc    : 参数传递

Python中的变量赋值规则:
1. 变量的赋值,只是表示让变量指向了某个对象,并不表示拷贝对象给变量。而一个对象,可以被多个变量所指向
2. 可变对象(list、set、dict...)的改变,会影响所有指向该对象的变量
3. 对于不可变对象(int、str、tuple...)所有指向该对象的变量的值总是一样的,也不会改变.
   但是通过某些操作(+= 等等)更新不可变对象的值时,会返回一个新的对象,此时每个变量可能指向不同的对象
4. 使用del关键字,可以删除变量,之后该变量就无法被访问,但是并不会删除变量指向的对象
   变量指向的对象,会在GC是被垃圾回收

Python中的参数传递规则:
Python的参数传递是赋值传递(pass by assignment),或者叫作对象的引用传递(pass by object reference)
Python中所有的数据类型都是对象,所以参数传递时,只是让新变量与原变量指向相同的对象而已,并不存在值传递或是引用传递一说

如果对象是可变的,当其改变时,所有指向这个对象的变量都会改变
如果对象不可变,简单的赋值只能改变其中一个变量的值,其余变量则不受影响
"""


def func1(b: int):
    """这里只是将变量b指向了新对象2,并不会修改外部的变量a"""
    b = 2


def func2(b: int) -> int:
    """通过返回值,修改对象的值"""
    b = 2
    return b


def func3(l: list[int]):
    """
    将可变对象通过函数的参数传递
    在函数内部修改对象的值,会影响外部所有指向该对象的变量
    """
    l.append(4)


def func4(l: list[int]):
    """
    通过+=操作,将l指向一个新的list对象,并不会影响外部指向之前list的变量
    """

    l = l + [4]


def func5(l: list[int]) -> list[int]:
    """
    通过返回值,可以修改外部变量
    """
    l = l + [4]
    return l


if __name__ == '__main__':
    a = 1
    print(f'before invoke func1, a = {a}')  # a = 1
    func1(a)
    print(f'after invoke func1, a = {a}')  # a = 1

    a = func2(a)
    print(f'after invoke func2, a = {a}')  # a = 2

    l1 = [1, 2, 3]
    print(f'before invoke func3, l1 = {l1}')  # l1 = [1, 2, 3]
    func3(l1)
    print(f'after invoke func3, l1 = {l1}')  # l1 = [1, 2, 3, 4]

    l2 = [1, 2, 3]
    print(f'before invoke func4, l2 = {l2}')  # l2 = [1, 2, 3]
    func4(l2)
    print(f'after invoke func4, l2 = {l2}')  # l2 = [1, 2, 3]

    l3 = [1, 2, 3]
    print(f'before invoke func5, l3 = {l3}')  # l3 = [1, 2, 3]
    l3 = func5(l3)
    print(f'after invoke func5, l3 = {l3}')  # l3 = [1, 2, 3, 4]
